package edu.nf.llmtest.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.util.retry.Retry;

import java.time.Duration;
import java.util.List;
import java.util.Map;

/**
 * @ Author bin
 * @ Create  2025/11/4 15:54
 * 嵌入服务
 **/
@Service
@Slf4j
public class JinaEmbeddingService {

    @Value("${jina.api-key}")
    private String apiKey;

    private final WebClient webClient;

    public JinaEmbeddingService() {
        // 配置 HttpClient：连接超时、读写超时
        HttpClient httpClient = HttpClient.create()
                .responseTimeout(Duration.ofSeconds(30))  // 响应超时 30 秒
                .doOnConnected(conn ->
                        conn.addHandlerLast(new io.netty.handler.timeout.ReadTimeoutHandler(30))
                                .addHandlerLast(new io.netty.handler.timeout.WriteTimeoutHandler(30))
                );

        this.webClient = WebClient.builder()
                .baseUrl("https://api.jina.ai/v1/embeddings")
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .build();
    }

    /**
     * 生成向量（响应式版本，带重试机制）
     * @param text 输入文本
     * @return Mono包装的向量列表
     */
    public Mono<List<Float>> embedText(String text) {
        Map<String, Object> request = Map.of(
                "model", "jina-embeddings-v2-base-zh",
                "input", text
        );

        return webClient.post()
                .header("Authorization", "Bearer " + apiKey)
                .bodyValue(request)
                .retrieve()
                .bodyToMono(Map.class)
                .map(response -> {
                    List<Double> vector = (List<Double>) ((Map<String, Object>) ((List<?>) response.get("data")).get(0)).get("embedding");
                    return vector.stream().map(Double::floatValue).toList();
                })
                .retryWhen(Retry.backoff(3, Duration.ofSeconds(2))  // 最多重试3次，每次间隔2秒
                        .maxBackoff(Duration.ofSeconds(10))           // 最大退避时间10秒
                        .doBeforeRetry(retrySignal ->
                                log.warn("🔄 Jina API 调用失败，正在重试 ({}/3)，原因: {}",
                                        retrySignal.totalRetries() + 1,
                                        retrySignal.failure().getMessage())
                        )
                )
                .doOnError(e -> log.error("❌ Jina API 调用最终失败: {}", e.getMessage()));
    }
}
